package org.example.node;

import com.google.common.collect.Lists;
import com.sun.tools.javac.util.Assert;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.apache.commons.collections.CollectionUtils;
import org.example.BalancePlusTree;
import org.example.bo.SearchResultBO;
import org.example.bo.SimpleEntry;

import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import static org.example.enums.SearchResultEnum.FOUND;

/**
 * 叶子结点
 *
 * @author lik
 */
@EqualsAndHashCode(callSuper = false)
@Data
public class LeafNode<K extends Comparable<K>, V> extends AbstractNode<K, V> {

    /**
     * 父节点
     */
    private IndexNode<K, V> parent;

    /**
     * 数据
     */
    private List<Map.Entry<K, V>> dataList;

    /**
     * 下一个叶子节点
     */
    private LeafNode<K, V> nextLeafNode;

    /**
     * 前一个叶子结点
     */
    private LeafNode<K, V> previousLeafNode;

    /**
     * 根据key查询对应value
     *
     * @param key key
     * @return V
     */
    @Override
    public V query(K key) {
        List<K> keyList = dataList.stream().map(Map.Entry::getKey).collect(Collectors.toList());
        SearchResultBO searchResult = commonBinarySearch(keyList, key);
        if (searchResult.getResult() == FOUND) {
            return dataList.get(searchResult.getPosition()).getValue();
        }
        return null;
    }

    @Override
    public void setParent(AbstractNode<K, V> parent) {
        if (parent instanceof IndexNode) {
            this.parent = (IndexNode<K, V>) parent;
            return;
        }
        throw new IllegalArgumentException("父类类型不匹配哦");
    }

    /**
     * 插入数据
     *
     * @param key   key
     * @param value value
     */
    @Override
    public void insertOrUpdate(K key, V value, BalancePlusTree<K, V> balancePlusTree) {
        Map.Entry<K, V> newVal = new SimpleEntry<>(key, value);
        if (CollectionUtils.isEmpty(dataList)) {
            // 空直接插入
            dataList = Lists.newArrayListWithCapacity(DEGREE);
            dataList.add(newVal);
        } else {
            // 直接插入或者更新（使用二分查找）
            List<K> keyList = dataList.stream().map(Map.Entry::getKey).collect(Collectors.toList());
            SearchResultBO searchResult = commonBinarySearch(keyList, key);
            if (searchResult.getResult() == FOUND) {
                // 更新 或者 抛出 DuplicateKeyException
                dataList.get(searchResult.getPosition()).setValue(value);
            } else {
                // 插入指定位置
                K currentKey = null;
                if (searchResult.getPosition() == 0) {
                    currentKey = getMinimumKey();
                }
                dataList.add(searchResult.getPosition(), newVal);
                if (currentKey != null && parent != null) {
                    parent.updateIndex(currentKey, newVal.getKey());
                }

            }
        }

        // 大于节点的度
        if (dataList.size() > DEGREE) {
            // 分裂，平衡树
            division(balancePlusTree);
        }
    }

    private void division(BalancePlusTree<K, V> balancePlusTree) {
        // 中间值
        int middle = dataList.size() / 2 + 1;

        // 分裂一个左节点
        LeafNode<K, V> left = new LeafNode<>();
        left.setDataList(Lists.newArrayList(dataList.subList(0, middle)));

        // 分裂一个右节点
        LeafNode<K, V> right = new LeafNode<>();
        right.setDataList(Lists.newArrayList(dataList.subList(middle, dataList.size())));

        // 链表设值
        left.setPreviousLeafNode(previousLeafNode);
        left.setNextLeafNode(right);

        right.setPreviousLeafNode(left);
        right.setNextLeafNode(nextLeafNode);

        if (previousLeafNode == null) {
            // 没有前节点，当前节点就是最左节点
            balancePlusTree.setLeftmostLeafNode(left);
        } else {
            previousLeafNode.setNextLeafNode(left);
        }

        SimpleEntry<K, AbstractNode<K, V>> entry1 = new SimpleEntry<>(left.getMinimumKey(), left);
        SimpleEntry<K, AbstractNode<K, V>> entry2 = new SimpleEntry<>(right.getMinimumKey(), right);

        if (parent == null) {
            // 如果父节点为空，那么当前节点就是根节点，分裂后需要新增父节点
            IndexNode<K, V> parent = new IndexNode<>();
            List<Map.Entry<K, AbstractNode<K, V>>> children = Lists.newArrayListWithCapacity(DEGREE);
            balancePlusTree.setRoot(parent);

            children.add(entry1);
            children.add(entry2);
            parent.setChildren(children);

            left.setParent(parent);
            right.setParent(parent);
        } else {
            left.setParent(parent);
            right.setParent(parent);
            // 父节点添加分裂后的子节点
            parent.addChildren(new SimpleEntry<>(getMinimumKey(), this), entry1, entry2, balancePlusTree);
        }
    }

    @Override
    public K getMinimumKey() {
        if (CollectionUtils.isNotEmpty(dataList)) {
            return dataList.get(0).getKey();
        }
        return null;
    }

    @Override
    public void delete(K key) {
        if (CollectionUtils.isNotEmpty(dataList)) {
            List<K> keyList = dataList.stream().map(Map.Entry::getKey).collect(Collectors.toList());
            SearchResultBO searchResult = commonBinarySearch(keyList, key);
            if (searchResult.getResult() == FOUND) {
                // 当前节点原始的key
                K oldKey = getMinimumKey();
                // 移除数据
                dataList.remove((int) searchResult.getPosition());
                // 检查当前节点的平衡
                if (dataList.size() < MINIMUM_VALUE && parent != null) {
                    // 往左右兄弟节点借
                    if (previousLeafNode != null) {
                        // 左边兄弟如果借了，previousAfterSize就是调整之后的数据长度。
                        // 也是左边兄弟最后数据的位置
                        int previousAfterSize = previousLeafNode.getDataList().size() - 1;
                        if (previousAfterSize >= MINIMUM_VALUE) {
                            // 左边的兄弟说可以借
                            Map.Entry<K, V> borrowEntry = previousLeafNode.getDataList().get(previousAfterSize);
                            dataList.add(0, borrowEntry);
                            previousLeafNode.getDataList().remove(previousAfterSize);
                            // 更新父节点索引
                            parent.updateIndex(oldKey, borrowEntry.getKey());
                        } else {
                            // 左边的兄弟说 我也不够了，那就合并了呗，往左合并
                            previousLeafNode.getDataList().addAll(dataList);
                            // 当前节点被合并后，需要把后面节点的引用给左边的兄弟
                            previousLeafNode.setNextLeafNode(nextLeafNode);
                            // 父节点移除当前叶子结点
                            parent.removeIndex(oldKey);
                        }
                    } else if (nextLeafNode != null && nextLeafNode.getParent() != null) {
                        // 右边的兄弟节点
                        int nextAfterSize = nextLeafNode.getDataList().size() - 1;
                        if (nextAfterSize >= MINIMUM_VALUE) {
                            // 右边的兄弟说可以借
                            Map.Entry<K, V> borrowEntry = nextLeafNode.getDataList().get(0);
                            dataList.add(borrowEntry);
                            nextLeafNode.getDataList().remove(0);
                            // 更新节点索引
                            nextLeafNode.getParent().updateIndex(borrowEntry.getKey(), nextLeafNode.getMinimumKey());
                            // 当前节点如果删除的是0号位的索引值，需要更新父节点索引
                            if (searchResult.getPosition() == 0) {
                                parent.updateIndex(oldKey, getMinimumKey());
                            }
                        } else {
                            // 右边的兄弟说 我也不够了，那就合并了呗，往当前节点合并
                            dataList.addAll(nextLeafNode.getDataList());
                            // 右边的兄弟没了，把右右边的兄弟带上
                            nextLeafNode = nextLeafNode.getNextLeafNode();
                            // 父节点移除右边叶子结点
                            nextLeafNode.getParent().removeIndex(oldKey);
                        }
                    }
                } else if (searchResult.getPosition() == 0 && parent != null) {
                    // 如果删除的是0号位的索引值，需要更新父节点索引
                    parent.updateIndex(oldKey, getMinimumKey());
                }
            }
        } else {
            System.out.println("木有找到数据");
        }
    }

}
